﻿//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Core.h".
//-------------------------------------------------------------------

#ifndef _UXS_AUTOPTR_TYPE_H
#define _UXS_AUTOPTR_TYPE_H

#pragma once

#include "../Defines/Defines.h"

namespace UX_STL
{
namespace UXTypes
{

	//
	// Auto Ptr Strategy
	//

	template <typename T>
	struct TAutoPtrStrategy
	{
		static void Delete(T *ptr)	{ delete ptr; }
	};
	

#	define AUTO_POINTER_TYPE( _type )					::UX_STL::UXTypes::AutoPtr< _type >
#	define AUTO_POINTER( _type )						typedef AUTO_POINTER_TYPE( _type )	_type##Ptr


	//
	// Auto Ptr
	//

#	define TAutoPtr	AutoPtr

	template <typename T, typename B = T, typename S = TAutoPtrStrategy<B> >
	struct TAutoPtr
	{
	// types
	public:
		typedef TAutoPtr< T, B, S >		Self;
		typedef T						value_t;
		

	// variables
	private:
		T	*_ptr;


	// methods
	private:
		void _Delete()
		{
			if ( _ptr != null )
			{
				S::Delete( (B*)_ptr );
				_ptr = null;
			}
		}


	public:
		TAutoPtr () : _ptr(null)
		{}
		

		TAutoPtr (T *p) : _ptr(p)
		{}

		
		TAutoPtr (Self &other) : _ptr(null)
		{
			_ptr = other._ptr;
			other._ptr = null;

		}
		

		RVALUE_REFERENCE_ONLY(
			TAutoPtr (Self &&other) : _ptr(other._ptr)
			{
				other._ptr = null;
			}
		)


		~TAutoPtr()
		{
			_Delete();
		}


		template <typename T2>
		Self & operator = (T2 *right)
		{
			if ( _ptr == right ) {
				WARNING( "" );
				return *this;
			}

			_Delete();
			_ptr = right;
			return *this;
		}


		Self & operator = (T *right)
		{
			if ( right != null and _ptr == right ) {
				WARNING( "" );
				return *this;
			}

			_Delete();
			_ptr = right;
			return *this;
		}


		template <typename T2>
		Self & operator = (TAutoPtr<T2,B,S> &right)
		{
			if ( (void*)_ptr == (void*)right._ptr ) {
				WARNING( "" );
				return *this;
			}

			_Delete();
			_ptr = right._ptr;
			right._ptr = null;
			return *this;
		}


		Self & operator = (Self &right)
		{
			if ( _ptr == right._ptr ) {
				WARNING( "" );
				return *this;
			}

			_Delete();
			_ptr = right._ptr;
			right._ptr = null;
			return *this;
		}


		T * operator -> () const
		{
			ASSUME( _ptr != null );
			return _ptr;
		}


		T & operator * () const
		{
			ASSUME( _ptr != null );
			return *_ptr;
		}


		T *& ref()
		{
			return _ptr;
		}


		T * ptr()
		{
			ASSUME( _ptr != null );
			return _ptr;
		}

		const T * const ptr() const
		{
			ASSUME( _ptr != null );
			return _ptr;
		}


		bool Empty() const
		{
			return ( _ptr == null );
		}


		bool IsNull() const
		{
			return ( _ptr == null );
		}


		bool IsNotNull() const
		{
			return not IsNull();
		}


		void Reset()
		{
			_ptr = null;
		}


		template <typename T2>
		TAutoPtr<T2,B,S> To()
		{
			return TAutoPtr<T2,B,S>(this);
		}
		

		bool operator == (const T *right) const
		{
			return _ptr == right;
		}

		
		bool operator == (const Self &right) const
		{
			return _ptr == right._ptr;
		}

		
		bool operator != (const T *right) const
		{
			return _ptr != right;
		}
		

		bool operator != (const Self &right) const
		{
			return _ptr != right._ptr;
		}

		
		bool operator ! () const
		{
			return _ptr != null;
		}


		template <typename T2>
		static Self CreateCopy (const T2& value)
		{
			return Self( new T( value ) );
		}
	};

#	undef TAutoPtr

//-------------------------------------------------------------------

}	// UXTypes
}	// UX_STL

#endif	// _UXS_AUTOPTR_TYPE_H
